
QSettings类提供了与平台无关的设置信息持久化存储功能。
用户通常希望各个软件能够在不同的会话之间记住它的设置信息(窗口尺寸及位置、选项等等)。对于这种信息的存储途径,在Unix系统中,由于缺少一种标准,狠多程序(包括KDE中的程序)都是使用INI格式的文本文件来存储。
QSettings是对于这类技术的一种抽象 ,使得妳可以以一种可移植的方式来保存及恢复程序设置信息。它还支持 自定义的存储格式 。 。
QSettings的编程接口是基于 QVariant 的 ,这使得妳可以保存大部分基于值的类型,例如 QString 、 QRect 和 QImage ,而且是毫无压力地保存。
如果妳只是需要使用一种非持久化的基于内存的数据结构的话 ,那么就应当使用 QMap < QString , QVariant > 。
当妳创建一个QSettings对象时,妳必须传入妳的公司或组织的名字,以及程序的名字。例如,假设妳的软件名字是Star Runner,并且公司名字是MySoft,那么,应当这样来构造QSettings对象:
QSettings settings("MySoft", "Star Runner");
QSettings对象可以在栈上创建也可以在堆上 (也就是说 ,使用new语句 ) 创建 。对 QSettings 的构造及销毁是非常快的 。
如果妳需要在程序中多处使用QSettings的话 ,那么就应当使用 QCoreApplication::setOrganizationName ()和 QCoreApplication::setApplicationName ()来指定组织名字及程序名字 ,然后再使用默认的 QSettings构造函数 :
QCoreApplication ::setOrganizationName("MySoft");
QCoreApplication ::setOrganizationDomain("mysoft.com");
QCoreApplication ::setApplicationName("Star Runner");
...
QSettings settings;
(这里 ,我们还指定了组织的互联网域名。如果未设置域名 ,则会根据组织名字来推断出一个伪域名。参考后文中的 平台相关的注意事项 以了解详细信息。)
QSettings储存的是设置信息。每条设置信息都由一个 QString 和一个 QVariant 组成 ,前者指定的是这条设置信息的名字( 键 ),后者储存的是与这个键关联的数据 。要写入一条设置信息的话 ,就使用 setValue () 。例如:
settings.setValue("editor/wrapMargin", 68);
如果已经有了一条与之同名的设置信息的话 ,则已有的设置信息值会被新的值覆盖。出于性能考虑,这里所做的改变不一定会立即写入到持久化存储设备中去 。 (妳可以随时调用 sync ()来提交妳所作的变更 。 )
妳可以使用 value ()来将某条设置信息读取回来 :
int margin = settings.value("editor/wrapMargin").toInt();
如果不存在与指定名字对应的设备信息,那么QSettings会返回一个空的 (null) QVariant (可以被转换为数字0) 。妳可以给 value ()传入第二个参数 ,以指定一个默认值:
int margin = settings.value("editor/wrapMargin", 80).toInt();
要测试某个键是否存在的话 ,可以调用 contains () 。要想删除与某个键相关联的设置信息的话 ,就调用 remove ()。要获取所有键组成的列表 ,就调用 allKeys ()。要删除所有的键,就调用 clear () 。
因为 QVariant 是 QtCore 库中的一部分,所以 ,它无法为像 QColor 、 QImage 和 QPixmap 这样的数据类型提供转换函数 ,这些数据类型是 QtGui 中的一部分。 换句话说,在 QVariant 中不存在 toColor() 、 toImage()和toPixmap()函数 。
不过 ,妳可以使用 QVariant::value ()或 qVariantValue ()模板函数 。例如:
QSettings settings("MySoft", "Star Runner");
QColor color = settings. value ("DataPump/bgcolor").value< QColor >();
反向的转换(例如,从 QColor 转换为 QVariant )对于 QVariant 所支持的所有数据类型都是自动进行的 ,其中包括与图形界面相关的类型:
QSettings settings("MySoft", "Star Runner");
QColor color = palette().background().color();
settings. setValue ("DataPump/bgcolor", color);
使用 qRegisterMetaType ()和 qRegisterMetaTypeStreamOperators ()注册过的自定义类型也可以用 QSettings 来存储 。
设置信息的键名可以包含任意的统一码 (Unicode)字符。
妳可以使用'/'字符作为分隔符来构造出由键名组成的层次结构,这与Unix 的文件名路径类似。例如:
settings.setValue("mainwindow/size", win->size());
settings.setValue("mainwindow/fullScreen", win->isFullScreen());
settings.setValue("outputpanel/visible", panel->isVisible());
如果妳想要保存或恢复拥有相同前缀的多条设置信息的话 ,那么,可以使用 beginGroup ()来指定前缀 ,日后再使用 endGroup ()来结束前缀。以下是一段拥有相同逻辑的代码 ,不过这次我们使用的是分组机制:
settings.beginGroup("mainwindow");
settings.setValue("size", win->size());
settings.setValue("fullScreen", win->isFullScreen());
settings.endGroup();
settings.beginGroup("outputpanel");
settings.setValue("visible", panel->isVisible());
settings.endGroup();
如果使用 beginGroup ()设置了一个分组,那么 ,大部分函数的行为也会相应地改变。分组可以递归设置 。
除了分组之外 , QSettings还支持一种"数组"概念。参考 beginReadArray ()和 beginWriteArray ()以了解细节 。
假设妳创建了一个QSettings 对象,它的组织名字是MySoft,程序名字是Star Runner。当妳查询某个值的时候,会按照顺序在四个位置中搜索:
1.与用户相关的针对Star Runner 程序的某个位置
2.与用户相关的针对MySoft的所有程序的某个位置
3.系统为Star Runner 程序指定的某个位置
4.系统为MySoft的所有程序指定的某个位置
(参考后文的 平台相关注意事项 ,以了解在Qt 支持的不同平台上分别都对应着哪些位置 。 )
如果在第一个位置找不到某个键的信息,则会继续到第二个位置去查找,依此类推。这使得妳可以存储系统级别或者组织级别的设置信息,并且又可以针对每个用户或者每个程序来覆盖其中的一些信息。要想关闭这个机制的话,就调用setFallbacksEnabled(false)。
尽管所有 4个位置的键都可以用于读取,但是,只有第一个文件 (与用户相关的针对当前程序的某个位置)可被用于写入。要想向其它的某个文件写入设置信息的话 ,就省略掉程序的名字并且/或者指定 QSettings::SystemScope (与 QSettings::UserScope 相对 ,后者是默认值 ) 。
来对着一个例子研究:
QSettings obj1("MySoft", "Star Runner");
QSettings obj2("MySoft");
QSettings obj3( QSettings ::SystemScope, "MySoft", "Star Runner");
QSettings obj4( QSettings ::SystemScope, "MySoft");
下表列出了上面构建的各个QSettings 对象分别访问的是哪个位置的设置信息。"X"表示该位置是与该QSettings 对象相关联的主要位置,被用于读取及写入操作;"o"表示该位置会在做读取操作时用于备胎。
|
位置 |
obj1 |
obj2 |
obj3 |
obj4 |
|
1. 用户,程序 |
X |
|||
|
2. 用户,组织 |
o |
X |
||
|
3. 系统,程序 |
o |
X |
||
|
4. 系统,组织 |
o |
o |
o |
X |
这个机制的美妙之处在于,它在Qt 支持的所有平台上都是正常工作的,同时它给予妳巨大的灵活性,还不需要妳指定任何的文件名。
If you want to如果妳想在所有平台上都使用INI文件 ,而不使用原生接口的话,那么,妳可以在 QSettings 的构造函数中传入 QSettings::IniFormat 作为第一个参数 ,接下来是作用域、组织名字和程序名字:
QSettings settings( QSettings ::IniFormat, QSettings ::UserScope,
"MySoft", "Star Runner");
设置信息编辑器 示例可用来试验使用不同的设置信息位置以及开关不同的备胎位置的效果 。
QSettings经常被用来储存图形用户界面程序的状态。以下示例演示了如何使用QSettings 来保存及恢复一个程序的主窗口的几何属性。
void MainWindow::writeSettings()
{
QSettings settings("Moose Soft", "Clipper");
settings.beginGroup("MainWindow");
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void MainWindow::readSettings()
{
QSettings settings("Moose Soft", "Clipper");
settings.beginGroup("MainWindow");
resize(settings.value("size", QSize (400, 400)).toSize());
move(settings.value("pos", QPoint (200, 200)).toPoint());
settings.endGroup();
}
参考 窗口几何属性 ,其中说明了,当妳需要恢复一个窗口的几何属性的时候,为什么应当使用 QWidget::resize ()和 QWidget::move (),而不是 QWidget::setGeometry ()。
这里的 readSettings() 和 writeSettings() 函数必须分别在主窗口的构造函数和关闭事件处理函数中调用 :
MainWindow::MainWindow()
{
...
readSettings();
}
void MainWindow::closeEvent( QCloseEvent *event)
{
if (userReallyWantsToQuit()) {
writeSettings();
event->accept();
} else {
event->ignore();
}
}
参考 程序 示例,那是一个使用QSettings 实现的自包含的示例。
QSettings是 可重入的 。这就意味着 ,妳可以在不同的线程中同时使用不同的 QSettings对象 。即使多个QSettings 对象引用的是硬盘上的同一个文件 ,也是安全的。如果通过某个QSettings 对象做了一项修改,那么 ,这项修改能够立即在同一进程中和对同一个位置的设置文件进行操作的其它QSettings 对象看到 。
QSettings可安全地用于在不同进程中 (可以是妳的程序被同时运行的不同实例,也可以是完全不同的程序)对同一个系统位置的设置信息进行读写操作。它使用询问式的文件锁 (advisory file locking)及一种智能合并算法来确保数据的完整性。注意 , sync ()会将其它进程中所做的变更引入进来(同时也将本QSettings 对象中的变更写入到设置信息文件中) 。
之前在 备胎机制 小节中提到过 , QSettings会将一个程序的设置信息储存在 4个位置,具体位置取决于该设置信息是针对单个用户的还是系统级别的,该设置信息是针对单个程序的还是组织级别的。为了简单地说明这个问题,我们假设这里所使用的组织叫做 MySoft ,程序叫做 Star Runner 。
在Unix系统中 ,如果所使用的格式是 原生格式 ,则会默认使用以下文件:
1. $HOME/.config/MySoft/Star Runner.conf (用于嵌入式Linux 的Qt: $HOME/Settings/MySoft/Star Runner.conf )
2. $HOME/.config/MySoft.conf (用于嵌入式Linux 的Qt: $HOME/Settings/MySoft.conf )
3. /etc/xdg/MySoft/Star Runner.conf
4. /etc/xdg/MySoft.conf
如果文件格式是 格式 ,则在Unix 系统中会使用以下文件:
1. $HOME/.config/MySoft/Star Runner.ini (用于嵌入式Linux 的Qt: $HOME/Settings/MySoft/Star Runner.ini )
2. $HOME/.config/MySoft.ini (用于嵌入式Linux 的Qt: $HOME/Settings/MySoft.ini )
3. /etc/xdg/MySoft/Star Runner.ini
4. /etc/xdg/MySoft.ini
.ini 和 .conf 文件的路径可使用 setPath ()来修改。在Unix中 ,用户可通过设置 XDG_CONFIG_HOME 环境变量来覆盖它们的值 ;参考 setPath ()以了解细节 。
某些时候 ,妳需要访问某个特定文件中储存的设置信息。在所有的平台上 ,如果妳想直接读取一个 INI文件的话 ,妳可以使用带两个参数的QSettings 构造函数 ,第一个参数是一个文件名 ,第二个参数是 QSettings::IniFormat 。例如:
QSettings settings("/home/petra/misc/myapp.ini",
QSettings ::IniFormat);
然后,妳就可以使用这个QSettings对象来读取及写入该文件中的设置信息。
虽然QSettings会尽力抹平受支持的不同平台之间的差异 ,但是,仍然存在着一些差异,当妳在移植程序的时候需要考虑:
•. 在Unix系统中 ,如果检测到当前是在NFS 文件系统 (或者AutoFS或CacheFS)中工作的话,则会禁用掉询问式文件锁功能,这是为了绕过NFS fcntl()实现中的一个问题 ,当statd 和lockd 未运行时该函数会永久挂起。
参考 QVariant 、 QSessionManager 、 设置信息编辑器示例 和 程序示例 。
未知美人
未知美人
HxLauncher: Launch Android applications by voice commands